package com.cm.sys.framework.mybatiesinterceptor;

import java.sql.Statement;
import java.util.List;
import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import com.alibaba.druid.util.JdbcConstants;
import com.cm.sys.framework.application.ApiResponseCode;
import com.cm.sys.framework.execption.BusinessException;

/***
 * mybaties sql拦截器 阻止多个表连查
 * 
 * @author yxq18
 *
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
    @Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
    @Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})})
public class SqlInterceptor implements Interceptor {

    private static final Logger logger = LoggerFactory.getLogger(SqlInterceptor.class);

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        Object target = invocation.getTarget();
        StatementHandler statementHandler = (StatementHandler)target;
        BoundSql boundSql = statementHandler.getBoundSql();
        String sql = boundSql.getSql(); // 获取sql
        logger.info("拦截到的sql【{}】", sql);

        // 格式化输出
        String result = SQLUtils.format(sql, JdbcConstants.MYSQL);
        System.out.println(result); // 缺省大写格式
        List<SQLStatement> stmtList = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);

        // 解析出的独立语句的个数

        if (stmtList.size() > 6) {
            throw new BusinessException(ApiResponseCode.JOIN_MORE.getCode(), ApiResponseCode.JOIN_MORE.getMessage());

        } else {
            for (int i = 0; i < stmtList.size(); i++) {

                SQLStatement stmt = stmtList.get(i);
                MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
                stmt.accept(visitor);
                if (visitor.getTables().size() > 4) {
                    throw new BusinessException(ApiResponseCode.JOIN_MORE.getCode(),
                        ApiResponseCode.JOIN_MORE.getMessage());
                }

            }
        }

        long start = System.currentTimeMillis();
        try {
            return invocation.proceed(); // sql运行
        } catch (Throwable t) {
            String.format("错误SQL=%s", sql);
            throw t;
        } finally {
            logger.info(String.format("耗时%s ms, SQL=%s", (System.currentTimeMillis() - start), sql));
        }

    }

    @Override
    public Object plugin(Object target) {
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        }
        return target;
    }

    @Override
    public void setProperties(Properties properties) {
        // TODO Auto-generated method stub

    }

}
